package com.test.learnkotlin

import android.app.Person

/*
解构声明
https://www.kotlincn.net/docs/reference/multi-declarations.html

有时把一个对象 解构 成很多变量会很方便


Kotlin在实际项目中的使用小结
https://blog.51cto.com/jun5753/4937939?b=totalstatistic


 */
fun main(args: Array<String>) {
    //// 现在，使用该函数：
    val (result, status) = function1("admin", "123456")
    println("result = $result , status = $status")
    val  (result2, status2) = Result("默认",100)
    println("result2 = $result2 , status2 = $status2")
    //result = 登录成功 , status = 200
    //result2 = 默认 , status2 = 100

    println("----------------------------------------------------------------------------------")


    //解构声明和映射
    //可能遍历一个映射（map）最好的方式就是这样：
    val tempMap = mapOf("kotlin" to "andorid", "java" to "andorid")
    for((key, value) in tempMap){
        println("key = $key , value = $value")
    }
    //key = kotlin , value = andorid
    //key = java , value = andorid


    //为使其能用，我们应该
    //
    //通过提供一个 iterator() 函数将映射表示为一个值的序列；
    //通过提供函数 component1() 和 component2() 来将每个元素呈现为一对。
    //当然事实上，标准库提供了这样的扩展：
    //
    //operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator()
    //operator fun <K, V> Map.Entry<K, V>.component1() = getKey()
    //operator fun <K, V> Map.Entry<K, V>.component2() = getValue()

    println("----------------------------------------------------------------------------------")


    //下划线用于未使用的变量（自 1.1 起）
    //如果在解构声明中你不需要某个变量，那么可以用下划线取代其名称：
    val (_, status3) = function1("admin", "123456")
    //对于以这种方式跳过的组件，不会调用相应的 componentN() 操作符函数。


    println("------------------  在 lambda 表达式中解构 -----------------------------------------------")
    //在 lambda 表达式中解构（自 1.1 起）
    //你可以对 lambda 表达式参数使用解构声明语法。 如果 lambda 表达式具有 Pair 类型（或者 Map.Entry 或任何其他具有相应 componentN 函数的类型）的参数，那么可以通过将它们放在括号中来引入多个新参数来取代单个新参数：
    //
    tempMap.mapValues { entry -> println("${entry.key} , ${entry.value}") }
    tempMap.mapValues { (key, value) -> println("$key , $value") }

    println("----------------------------------------------------------------------------------")


    //注意声明两个参数和声明一个解构对来取代单个参数之间的区别：
    //
    //{ a //-> …… } // 一个参数
    //{ a, b //-> …… } // 两个参数
    //{ (a, b) //-> …… } // 一个解构对
    //{ (a, b), c //-> …… } // 一个解构对以及其他参数



    //如果解构的参数中的一个组件未使用，那么可以将其替换为下划线，以避免编造其名称：
    //
    //map.mapValues { (_, value) -> "$value!" }
    //你可以指定整个解构的参数的类型或者分别指定特定组件的类型：
    //
    //map.mapValues { (_, value): Map.Entry<Int, String> -> "$value!" }
    //​
    //map.mapValues { (_, value: String) -> "$value!" }

    println("----------------------------------------------------------------------------------")


    //类型检测与类型转换：“is”与“as”
    //is 与 !is 操作符
    //我们可以在运行时通过使用 is 操作符或其否定形式 !is 来检测对象是否符合给定类型：

    var tempVar = 1
    when(tempVar){
        is Int -> println((tempVar + 1))
//        is String -> println(tempVar.length)
//        is IntArray -> println(tempVar.sum())
    }

    println("----------------------------------------------------------------------------------")
    //“不安全的”转换操作符
    //通常，如果转换是不可能的，转换操作符会抛出一个异常。因此，我们称之为不安全的。 Kotlin 中的不安全转换由中缀操作符 as（参见operator precedence）完成：
    //
    //val x: String = y as String
    //请注意，null 不能转换为 String 因该类型不是可空的， 即如果 y 为空，上面的代码会抛出一个异常。 为了让这样的代码用于可空值，请在类型转换的右侧使用可空类型：
    //
    //val x: String? = y as String?


    println("----------------------------------------------------------------------------------")


    //“安全的”（可空）转换操作符
    //为了避免抛出异常，可以使用安全转换操作符 as?，它可以在失败时返回 null：
    //
    //val x: String? = y as? String
    //请注意，尽管事实上 as? 的右边是一个非空类型的 String，但是其转换的结果是可空的。

    println("----------------------------------------------------------------------------------")


    /*
        相等性
        Kotlin 中有两种类型的相等性：

        结构相等（用 equals() 检测）；
        引用相等（两个引用指向同一对象）。
        结构相等
        结构相等由 ==（以及其否定形式 !=）操作判断。按照惯例，像 a == b 这样的表达式会翻译成：

        a?.equals(b) ?: (b === null)
        也就是说如果 a 不是 null 则调用 equals(Any?) 函数，否则（即 a 是 null）检测 b 是否与 null 引用相等。

        请注意，当与 null 显式比较时完全没必要优化你的代码：a == null 会被自动转换为 a === null。

        如需提供自定义的相等检测实现，请覆盖 equals(other: Any?): Boolean 函数。名称相同但签名不同的函数，如 equals(other: Foo) 并不会影响操作符 == 与 != 的相等性检测。

        结构相等与 Comparable<……> 接口定义的比较无关，因此只有自定义的 equals(Any?) 实现可能会影响该操作符的行为。

     */


    /*
        安全的调用
        你的第二个选择是安全调用操作符，写作 ?.：

        val a = "Kotlin"
        val b: String? = null
        println(b?.length)
        println(a?.length) // 无需安全调用



        Elvis 操作符
        当我们有一个可空的引用 b 时，我们可以说“如果 b 非空，我使用它；否则使用某个非空的值”：

        val l: Int = if (b != null) b.length else -1
        除了完整的 if-表达式，这还可以通过 Elvis 操作符表达，写作 ?:：

        val l = b?.length ?: -1
        如果 ?: 左侧表达式非空，elvis 操作符就返回其左侧表达式，否则返回右侧表达式。 请注意，当且仅当左侧为空时，才会对右侧表达式求值。

    */
}

/*
从函数中返回两个变量
让我们假设我们需要从一个函数返回两个东西。例如，一个结果对象和一个某种状态。 在 Kotlin 中一个简洁的实现方式是声明一个数据类 并返回其实例：
 */
data class Result(val result: String, val status: Int)

fun function1(name: String, pwd: String): Result {
    //各种计算
    var result = "登录失败"
    var status = -1
    if (name.equals("admin", false) && pwd.equals("123456")) {
        result = "登录成功"
        status = 200
    }
    return Result(result, status)
}